package cn.caplike.demo.repository.design.pattern.visitor;

import java.util.ArrayList;
import java.util.List;

/**
 * 抽象访问者.<br>
 * 定义一个访问具体元素的接口, 为每个具体元素类对应一个访问操作 visit(), 该操作中的参数类型标识了被访问的具体元素.
 */
interface Visitor {
    void visit(ConcreteElementA element);

    void visit(ConcreteElementB element);
}

//抽象元素类
interface Element {
    void accept(Visitor visitor);
}

/**
 * Description: 访问者 (Visitor) 模式示例.<br>
 * 结构图: <br<
 * <img src="http://c.biancheng.net/uploads/allimg/181119/3-1Q119101429D6.gif">
 *
 * @author LiKe
 * @version 1.0.0
 * @date 2021-07-09 13:25
 */
public class VisitorPattern {
    public static void main(String[] args) {

        ObjectStructure os = new ObjectStructure();
        os.add(new ConcreteElementA());
        os.add(new ConcreteElementB());

        Visitor visitor = new ConcreteVisitorA();
        os.accept(visitor);

        System.out.println("------------------------");

        visitor = new ConcreteVisitorB();
        os.accept(visitor);
    }
}

//具体访问者A类
class ConcreteVisitorA implements Visitor {
    public void visit(ConcreteElementA element) {
        System.out.println("具体访问者A访问-->" + element.operationA());
    }

    public void visit(ConcreteElementB element) {
        System.out.println("具体访问者A访问-->" + element.operationB());
    }
}

//具体访问者B类
class ConcreteVisitorB implements Visitor {
    public void visit(ConcreteElementA element) {
        System.out.println("具体访问者B访问-->" + element.operationA());
    }

    public void visit(ConcreteElementB element) {
        System.out.println("具体访问者B访问-->" + element.operationB());
    }
}

//具体元素A类
class ConcreteElementA implements Element {
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    public String operationA() {
        return "具体元素A的操作。";
    }
}

//具体元素B类
class ConcreteElementB implements Element {
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    public String operationB() {
        return "具体元素B的操作。";
    }
}

//对象结构角色
class ObjectStructure {
    private final List<Element> list = new ArrayList<>();

    public void accept(Visitor visitor) {
        for (Element element : list) {
            element.accept(visitor);
        }
    }

    public void add(Element element) {
        list.add(element);
    }

    @SuppressWarnings("unused")
    public void remove(Element element) {
        list.remove(element);
    }
}
